package za.org.jcicada.confss.impl;

import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import za.org.jcicada.genss.sensor.impl.InvalidSensorValue;
import za.org.jcicada.genss.sensor.impl.Sensor;
import za.org.jcicada.genss.sensor.impl.StatusStrategyFactory;
import za.org.jcicada.genss.sensor.impl.TypeFloat;
import za.org.jcicada.genss.sensor.impl.TypeInt;

/**
 * Class which uses PerformanceMonitor to measure cpu usage and update a sensor.
 * Starts a timer in initialize and cancels the task in shutdown.
 * @author rcrida
 */
public class CpuUsage {

    /** Logger object used for logging messages. */
    private static final Log logger = LogFactory.getLog(CpuUsage.class);

	private PerformanceMonitor performanceMonitor = new PerformanceMonitor();
		
	private TimerTask task;
	
	private ThreadGroup initialGroup;
	
    /** Sensor representing the cpu usage of the subsystem. */
    private Sensor cpuSensor = new Sensor(TypeFloat.getInstance(0, 100), "cpu", "GenSS CPU sensor", "%");
    
    /** Sensor representing the memory usage of the subsystem. */
    private Sensor memorySensor = new Sensor(TypeFloat.getInstance(0, Float.MAX_VALUE), "memory", "GenSS Memory sensor", "MB");
    
    /** Sensor representing the number of threads. */
    private Sensor threadSensor = new Sensor(TypeInt.getInstance(0, Integer.MAX_VALUE), "threads", "GenSS Thread count sensor", "threads");

    public CpuUsage(ConfssDynamicConfiguration config) {
    	cpuSensor.setStatusStrategy(StatusStrategyFactory.createStatusStrategy(cpuSensor, config.cpuStatusStrategy));
    	memorySensor.setStatusStrategy(StatusStrategyFactory.createStatusStrategy(memorySensor, config.memoryStatusStrategy));
    	threadSensor.setStatusStrategy(StatusStrategyFactory.createStatusStrategy(threadSensor, config.threadStatusStrategy));
    }
    
	public Sensor[] getSensors() {
		return new Sensor[]{cpuSensor, memorySensor, threadSensor};
	}
	
	public void initialize(Timer timer, long period_ms) {
		initialGroup = Thread.currentThread().getThreadGroup();
		while(initialGroup.getParent() != null) {
			initialGroup = initialGroup.getParent();
		}
		task = new TimerTask() {

			@Override
			public void run() {
				try {
					cpuSensor.setValue(new Float(performanceMonitor.getCpuUsage() * 100));
					memorySensor.setValue(new Float((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024)));
					threadSensor.setValue(initialGroup.activeCount());
				} catch(InvalidSensorValue ex) {
					logger.error(ex);
				}
			}
			
		};
		timer.scheduleAtFixedRate(task, 0L, period_ms);
	}
	
	public void shutdown() {
		task.cancel();
	}
}
